package com.elitel.frame.business.controller;

import com.alibaba.fastjson.JSON;
import com.elitel.common.exception.BusinessStatementException;
import com.elitel.common.exception.SingleModeMismatchException;
import com.elitel.common.messageQueue.RabbitMQHelper;
import com.elitel.common.utils.LogTraceUtil;
import com.elitel.common.utils.LogTraceUtil.LogTraceTask;
import com.elitel.common.utils.LogTraceUtil.LogTracer;
import com.elitel.common.utils.XCommonUtils;
import com.elitel.frame.base.component.RedisCacheComponent;
import com.elitel.frame.base.component.TimeDelay;
import com.elitel.frame.base.service.BaseFieldaddonsService;
import com.elitel.frame.base.service.BaseFieldconfigService;
import com.elitel.frame.base.service.CfgFieldService;
import com.elitel.frame.business.service.SingleTableServerService;
import com.elitel.frame.business.service.TableFieldCommService;
import com.elitel.frame.main.entity.CfgDb;
import com.elitel.frame.main.entity.CfgExtend;
import com.elitel.frame.main.entity.CfgField;
import com.elitel.frame.main.entity.CfgTable;
import com.elitel.frame.main.entity.enums.ResponseStatusCodeEnum;
import com.elitel.frame.main.entity.vo.JsonDataResult;
import com.elitel.frame.main.entity.vo.PageResponseVo;
import com.elitel.frame.main.entity.vo.ServerStatistics;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Fanwenquan
 * @ClassName: SingleTableServerController
 * @Description: 单表服务增删改查提供端
 * @date 2017年8月3日 下午3:07:53
 */
@RestController
@RequestMapping("/business/singleServer")
@Api(value = "/business/singleServer", tags = "单表服务接口")
@Slf4j
public class SingleTableServerController {

    private static final Logger logger = LoggerFactory.getLogger(SingleTableServerController.class);

    @Autowired
    private CfgFieldService cfgFieldService;
    @Autowired
    private SingleTableServerService singleTableServerService;
    @Autowired
    private BaseFieldconfigService baseFieldconfigService;
    @Autowired
    private BaseFieldaddonsService baseFieldaddonsService;
    @Autowired
    private RedisCacheComponent redisCacheComponent;
//    @Autowired
//    private RedisCacheService redisCacheService;
    @Autowired
    private TableFieldCommService tableFieldCommService;

	@Autowired
	private RabbitMQHelper rabbitMQHelper;


    /**
     * @return Object
     * @throws
     * @Title: queryTableField
     * @Description: TODO(根据服务返回字段信息)
     * @author Fanwenquan
     */
    @RequestMapping(value = "/queryTableField", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "根据服务ID返回字段信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query")
    })
    public Object queryTableField(@RequestParam(value = "serviceID") String serviceID) {
        JsonDataResult jsonResult = new JsonDataResult();
        List<CfgField> cfgList = null;
        try {
            CfgExtend cfgExtend = redisCacheComponent.cfgExtendRedisCache(serviceID);
            cfgList = cfgFieldService.selectFieldByConfig(cfgExtend.getDtConfigId());
            jsonResult.setResult(0);
            jsonResult.setMessage("查询成功!");
            jsonResult.setData(cfgList);
        } catch (Exception e) {
            logger.error("单表服务查询字段信息异常:", e);
            jsonResult.setResult(1);
            jsonResult.setMessage("单表服务查询字段信息异常:" + e.getMessage());
        }

        return jsonResult;
    }

    /**
     * @return Object
     * @throws
     * @Title: queryTableQueryField
     * @Description: TODO(根据服务返回列表查询字段信息)
     * @author guoyanfei
     */
    @ApiOperation(value = "根据服务编码查询列表查询字段信息")
    @RequestMapping(value = "/queryTableQueryField", method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query")
    })
    @ResponseBody
    public Object queryTableQueryField(@RequestParam("serviceID") String serviceID) {
        JsonDataResult jsonResult = new JsonDataResult();
        try {
            List<Map<String, String>> result = getQueryTableQueryField(serviceID);
            jsonResult.setResult(0);
            jsonResult.setMessage("查询成功!");
            jsonResult.setData(result);
        } catch (Exception e) {
            logger.error("单表服务列表查询字段信息异常:", e);
            jsonResult.setResult(1);
            jsonResult.setMessage("单表服务列表查询字段信息异常:" + e.getMessage());
        }

        return jsonResult;
    }

    /**
     * TODO: 获取服务查询字段
     *
     * @param serviceID
     * @return
     */
    private List<Map<String, String>> getQueryTableQueryField(String serviceID) {
        List<Map<String, String>> result = new ArrayList<>();
        if (serviceID != null && serviceID.isEmpty() == false) {
            CfgExtend cfgExtend = redisCacheComponent.cfgExtendRedisCache(serviceID);
            if (cfgExtend != null) {
                CfgDb cfgDb = redisCacheComponent.cfgDBRedisCache(cfgExtend.getDbKey());
                result = tableFieldCommService.getTableQueryField(cfgDb, serviceID, 1, "");
            }
        }
        return result;
    }

    /**
     * @return Object
     * @throws
     * @Title: queryTableShowField
     * @Description: TODO(根据服务返回列表显示字段信息)
     * @author guoyanfei
     */
    @ApiOperation(value = "根据服务编码查询列表显示字段信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query")
    })
    @RequestMapping(value = "/queryTableShowField", method = RequestMethod.GET)
    @ResponseBody
    public Object queryTableShowField(@RequestParam("serviceID") String serviceID) {
        JsonDataResult jsonResult = new JsonDataResult();
        List<Map<String, String>> result = new ArrayList<>();
        try {
            CfgExtend cfgExtend = redisCacheComponent.cfgExtendRedisCache(serviceID);
            if (cfgExtend != null) {
                CfgDb cfgDb = redisCacheComponent.cfgDBRedisCache(cfgExtend.getDbKey());
                result = tableFieldCommService.getServiceShowField(cfgDb, serviceID, "1", "");
            }
            jsonResult.setResult(0);
            jsonResult.setMessage("查询成功!");
            jsonResult.setData(result);
        } catch (Exception e) {
            logger.error("单表服务列表查询展示字段信息异常:", e);
            jsonResult.setResult(1);
            jsonResult.setMessage("单表服务列表查询展示字段信息异常:" + e.getMessage());
        }

        return jsonResult;
    }


    /**
     * @return Object
     * @throws
     * @Title: isPading
     * @Description: TODO(查询是否分页)
     * @author guoyanfei
     */
    @ApiOperation(value = "根据服务编码查询服务是否分页")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query")
    })
    @RequestMapping(value = "/isPading", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> isPading(@RequestParam("serviceID") String serviceID) {
        Map<String, Object> result = new HashMap<>();
        CfgExtend cfgExtend = redisCacheComponent.cfgExtendRedisCache(serviceID);
        CfgTable cfgTable = redisCacheComponent.cfgTableRedisCache(cfgExtend.getDtConfigId(), cfgExtend.getDbKey());
        if (cfgExtend != null) result.put("isPage", cfgExtend.getIspagination() == 1);
        if (cfgTable != null) {
            result.put("serviceType", cfgTable.getDtTabletype());
            result.put("dtConfigId", cfgTable.getDtConfigId());
        }
        return result;
    }


    /**
     * @return Object
     * @throws
     * @Title: querySingleTable
     * @Description: TODO(单表服务分页查询)
     * @author Fanwenquan
     */
    @ApiOperation(value = "根据服务编码查询单表信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "serviceID", value = "服务编码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageNO", value = "当前页码", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页条数", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "conQuery", value = "查询条件集合", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "refCache", value = "是否强制刷新缓存", required = false, dataType = "String", paramType = "query")
    })
    @RequestMapping(value = "/querySingleTB", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public Object querySingleTable(HttpServletRequest request,
                                   @RequestParam("serviceID") String serviceID,
                                   String pageNO,
                                   String pageSize,
                                   String conQuery,
                                   String refCache) {

        LogTracer logTracer = LogTraceUtil.getLogTracer();
        LogTraceUtil.setLogTracer(logTracer);
        logTracer.setLogTracerName("singleTableFindService serviceGuid:"+serviceID);

        LogTraceTask logTraceTask = logTracer.recordTask("prepare relative parameter for service ");

        Map<String, Object> passConditionMap = handleConditionParam(request, conQuery);

        CfgExtend cfgExtend = redisCacheComponent.cfgExtendRedisCache(serviceID);
        // 获取服务查询字段
        List<Map<String, String>> queryField = getQueryTableQueryField(serviceID);

        ServerStatistics serverRecorder = ServerStatistics.createAndStartRecord();
        serverRecorder.recordSqlStartTime();
        try {
            // 日期延时计算
            Integer timeDelay = cfgExtend.getTimeDelay() == null ? 0 : cfgExtend.getTimeDelay();
            conQuery = TimeDelay.delay(conQuery, JSON.toJSONString(queryField), timeDelay);
            CfgDb cfgDB = redisCacheComponent.cfgDBRedisCache(cfgExtend.getDbKey());

            logTraceTask.endTask();

            PageResponseVo pageResponse = singleTableServerService.querySingleTBListPagination(cfgDB, cfgExtend, pageNO, pageSize, passConditionMap, refCache);

            pageResponse.computeFirstRowPosition(pageNO, pageSize);

            if(XCommonUtils.isSingleResponseMode(cfgExtend.getResponseMode())){
                List entityList = pageResponse.getRows();
                // pageResponse.getData exceed row throw ResponseModeException
                if(entityList == null || entityList.size() == 0)
                    return JsonDataResult.responseSuccess(null, cfgExtend.getResponseMode());

                if(entityList.size() > 1)
                    throw new SingleModeMismatchException("row size = " + entityList.size());

                // else get data , discard pageResponse directly return result (single row)
                return JsonDataResult.responseSuccess(entityList.get(0), cfgExtend.getResponseMode());

            }

            return JsonDataResult.responseSuccess(pageResponse, cfgExtend.getResponseMode());
        } catch (SingleModeMismatchException e){
            logger.error("从表查询单行模式异常: 查询数据大于一行 " + e.getMessage());
            return JsonDataResult.responseError(ResponseStatusCodeEnum.ERROR, "从表查询单行模式异常: 查询数据大于一行 ", cfgExtend.getResponseMode());

        } catch (BusinessStatementException e) {
            return JsonDataResult.responseError("exceptionMessage: " + e.getExceptionMessage() + "\r\n customMessage: " + e.getCustomMessage());

        } catch (Exception e) {
            logger.error("单表服务查询数据异常", e.getMessage());
            // unknow exception
            e.printStackTrace();
            return JsonDataResult.responseError(ResponseStatusCodeEnum.ERROR, "单表服务查询数据异常:" + e.getMessage(), cfgExtend.getResponseMode());

        } finally{
            // end log task
            LogTraceUtil.clearLogTracer();

            serverRecorder.recordSqlEndTime();
            serverRecorder.recordServerEndTime();
            serverRecorder.setServerName(cfgExtend.getServicename() + " (" + serviceID + ")");
            rabbitMQHelper.recordTimeConsumeIfNecessary(serverRecorder);
        }
    }

	private Map<String, Object> handleConditionParam(HttpServletRequest request, String conQuery) {
		Map<String, String[]> requestParameterMap = request.getParameterMap();
        Map<String, Object> passConditionMap = XCommonUtils.convertJsonStringToMap(conQuery);
        for(Map.Entry<String, String[]> paramterEntry : requestParameterMap.entrySet()){
            String paramName = paramterEntry.getKey();
            String paramValue = paramterEntry.getValue()[0];
            if(XCommonUtils.filterRequestParam(paramName))
                continue;

            passConditionMap.put(paramName, paramValue);
        }
		return passConditionMap;
	}
}
